
'''
1.生成qq扫码登录的url 返回给前端
2.用户扫码 进行登录 qq对用户进行鉴权
3.用户在手机上确认登录 ，返回一个code  code是代表登录成功德尔信息
4.code 返回给服务器，网站拿到后判断是否有账号绑定
    1.绑定过账号，直接登陆成功
    2.没有绑定过
        1.直接输入账号密码绑定 服务器判断账号密码，判断通过绑定
        2.没有账号 直接注册 注册后绑定
    3.绑定成功后 相当于登陆成功 ，返回token
5.用户携带token进行下一步请求


'''
from hashlib import sha256
import base64
import json, time
import hmac
import urllib
from flask import Blueprint,current_app,request,jsonify
from flask_restful import Api,Resource,reqparse
from urllib.parse import parse_qs, urlencode
import requests
import json
from common.models.users import *
from common.utils.token_utils import _generate_token
from werkzeug.security import check_password_hash

oauth_user_bp = Blueprint('oauth_user_bp',__name__,url_prefix='/oauth')
api = Api(oauth_user_bp)

class OauthUsers(Resource):
    def get(self):
        '''
        1.生成qq扫码登录的url 返回给前端
        https://graph.qq.com/oauth2.0/show?which=Login&display=pc&client_id=100490701&redirect_uri=https%3A%2F%2Fwww.zhihu.com%2Foauth%2Fcallback%2Fqqconn%3Faction%3Dlogin%26from%3D&response_type=code&scope=get_info%2Cget_user_info%2Cget_other_info%2Cadd_t%2Cadd_pic_t%2Cget_fanslist%2Cget_idollist%2Cadd_idol%2Cadd_share
        '''
        base_url = 'https://graph.qq.com/oauth2.0/authorize?'
        params = {
            'response_type':'code',
            'client_id':current_app.config['QQ_APP_ID'],
            'redirect_uri':current_app.config['QQ_REDIRECT_URL'],
            'state':current_app.config['QQ_STATE'],
            'scope':'get_user_info'# 返回qq用户的openid
        }
        data = urlencode(params)  # urlencode 会把字典转换成url的查询字符串
        url = base_url + data
        return {'url':url,'code':200}

class QQUserinfo(Resource):
    def code_value_(self,code):
        """根据返回的code 从qq 的token"""

        base_url = 'https://graph.qq.com/oauth2.0/token'
        if code:
            data = {
                'grant_type': "authorization_code",
                'client_id': current_app.config.get('QQ_APP_ID'),
                'client_secret': current_app.config.get("QQ_APP_KEY"),
                'code': code,
                'redirect_uri':current_app.config.get('QQ_REDIRECT_URL'),
            }
            resp = requests.request('GET',base_url, params=data)
            print("resp>>>", type(resp.text), resp.text)
            token_value = resp.text.split('&')[0][13:]
            return token_value

    def get_openid(self,token_v):
        '''获取qq的openid'''
        base_url = "https://graph.qq.com/oauth2.0/me"
        data = {'access_token': token_v, 'fmt': 'json'}
        # 获取扫码登录的用户信息
        resp = requests.request('GET', base_url, params=data)
        print("resp>>>", type(resp.text), resp.text)
        # 获取用户信息的openid, 扫码的用户信息
        # 根据用户信息判断用户是否绑定
        user_dict = json.loads(resp.text)
        openid = user_dict['openid']
        return openid

    def get_qq(self,openid,token):
        base_url = "https://graph.qq.com/user/get_user_info"
        data = {
            'oauth_consumer_key':current_app.config['QQ_APP_ID'],
            'access_token':token,
            'openid':openid
        }
        resp = requests.request('GET',base_url,params=data)
        nick_name = json.loads(resp.text)['nickname']
        return nick_name


    def get(self):
        """根据token 获取openid"""
        parser = reqparse.RequestParser()
        parser.add_argument('code')
        args = parser.parse_args()
        code = args.get('code')
        print('code>>>>', code)
        token_v = self.code_value_(code)
        openid = self.get_openid(token_v)
        return jsonify(code=200,msg='ok',uid=openid)

    def post(self):
        parse = reqparse.RequestParser()
        parse.add_argument('username')
        parse.add_argument('password')
        parse.add_argument('unid')
        args = parse.parse_args()
        openid = args['unid']
        account = args['username']
        password = args['password']
        # 判断账号是否注册过

        user = UserModel.query.filter_by(account=account).first()
        if not user:
            return jsonify(msg='请先在网站注册账号', code=500)
        res = check_password_hash(user.password,password)
        print(res)
        if not res:
            return jsonify(msg='密码不正确', code=500)
        oauth = OauthUser(uid=openid,user=user.uid,oauth_type='qq')
        db.session.add(oauth)
        db.session.commit()
        token, refresh_token = _generate_token(user)
        return jsonify(code=200, msg='登录成功',
               data={'token': token, 'uid': user.uid, 'account': user.account, 'refresh': refresh_token})


api.add_resource(OauthUsers,'/qq_url')
api.add_resource(QQUserinfo,'/userinfo')

"""
1. 前端页面点击钉钉图片, 后端返回给用户一个扫码登录的页面
2. 用户扫码登录, 确认登录后,返回给用户一个:http://127.0.0.1:8080/dingding_back?code=b61cf0c1f5e73df298243c2ba4a9a62f&state=STATE
3. 前端要把url中code的值获取到传递后端, 后端根据code 的值获取钉钉账号的信息
4. 根据钉钉账号的信息,判断是否和后台中的账号是否绑定
    1. 绑定直接登录
    2.没有绑定, 返回给前端一个绑定账号的页面,
    3. 用户输入后台的账号信息,进行绑定
5. 返回绑定后的token, 用户信息
"""


class DingDingOauthResource(Resource):
    def get(self):
        base_url = 'https://oapi.dingtalk.com/connect/qrconnect?appid=%s&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=%s'
        print(current_app.config.get('DING_REDIRECT_URI'),current_app.config.get('DING_APP_ID'))
        url = base_url % (current_app.config.get('DING_APP_ID'), current_app.config.get('DING_REDIRECT_URI'))
        # print('url>>',url)
        return {'url': url, 'code': 200}


class DingdingUserInfo(Resource):
    def get_ding_user(self, code):
        """获取登录的钉钉用户信息"""
        base_url = "https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature="
        appid = current_app.config.get('DING_APP_ID')
        appSecret = current_app.config.get('DING_SECRET_KEY')
        t = time.time()
        # 把时间戳转换成毫秒
        timestamp = str(int(round(t*1000)))
        # 构造签名
        signature = base64.b64encode(
            hmac.new(appSecret.encode('utf-8'), timestamp.encode('utf-8'), digestmod=sha256).digest())
        params = {
            'timestamp':timestamp,
            'accessKey':appid,
            'signature': urllib.parse.quote(signature.decode('utf-8')),
        }
        # params 是查询字符串参数
        # data 是请求体参数
        # header 指明传递参数的类型
        # 拼接url
        url = base_url + urllib.parse.quote(signature.decode('utf-8')) + "&timestamp="+timestamp + "&accessKey=" + appid
        print("url>>>>", url)
        resp = requests.post(url, data=json.dumps({'tmp_auth_code':code}), headers={'Content-Type': 'application/json'})
        print("ding的用户 resp>>>", resp.json())
        return resp.json()


    def get(self):
        """根据前端传来的code, 获取钉钉登录的用户信息"""
        parser = reqparse.RequestParser()
        parser.add_argument('code')
        args = parser.parse_args()
        code = args.get('code')
        print('code>>>>', code)

        # 根据code获取钉钉用户信息
        ding_user = self.get_ding_user(code)
        # ding_user = json.loads(res_json)
        if ding_user['errcode'] != 0:
            return jsonify(code=400,msg='获取钉钉用户失败')

        openid = ding_user['user_info']['openid']
        if openid:
            oauth_user = OauthUser.query.filter_by(uid=openid).first()
            if oauth_user:
                user = UserModel.query.filter_by(uid=oauth_user.user).first()
                token, refresh_token = _generate_token(user)
                return jsonify(code=200, msg='登录成功', data={'opid':openid,'token': token, 'uid': user.uid, 'account': user.account,
                                                           'refresh': refresh_token,'img':user.profile_photo})
            else:
                return jsonify(msg='没有绑定用户，请绑定',data={'opid':openid},code=401)
        return jsonify(msg='没有得到openid',code=400)

class BindUser(Resource):
    def post(self):
        parse = reqparse.RequestParser()
        parse.add_argument('account')
        parse.add_argument('password')
        parse.add_argument('unid')
        args = parse.parse_args()
        openid = args['unid']
        account = args['account']
        password = args['password']
        # 判断账号是否注册过

        user = UserModel.query.filter_by(account=account).first()
        if not user:
            return jsonify(msg='请先在网站注册账号', code=500)
        res = check_password_hash(user.password,password)
        print(res)
        if not res:
            return jsonify(msg='密码不正确', code=500)
        oauth = OauthUser(uid=openid,user=user.uid,oauth_type='dingding')
        db.session.add(oauth)
        db.session.commit()
        token, refresh_token = _generate_token(user)
        return jsonify(code=200, msg='登录成功',
               data={'token': token, 'uid': user.uid, 'account': user.account, 'refresh': refresh_token,'img':user.profile_photo})

api.add_resource(DingDingOauthResource, '/ding_url')
api.add_resource(DingdingUserInfo,'/ding_user')
api.add_resource(BindUser,'/bind_user')

